import math
import numpy as np
import itertools
import random
import hashlib
import time

frist = time.time()

#计算组合数
def CalCombiNum(n,m):
    return math.factorial(n) // (math.factorial(n - m) * math.factorial(m))  #直接使用math里的阶乘函数计算组合数
#判断是否为质数
def isPrime(n): 
  if n <= 1: 
    return False
  i = 2
  while i * i <= n: 
    if n % i == 0: 
      return False
    i += 1
  return True

#input(t,n)
t = 5
n = 9
#input security number
#d = 2
for d in range(2,3,2):
    #cal combination number
    N = CalCombiNum(n,t - 1)
    #combination types
    CombiTypes = np.zeros([d * N ,n]) 
    #generate Prime number 质数
    PrimeNumbers = []
    random.seed(8)
    int1 = 2e4
    int2 = 1e6
    while len(PrimeNumbers) < d * N:
        num1 = random.randint(int1,int2)
        if num1 not in PrimeNumbers:
            if isPrime(num1):
                PrimeNumbers.append(num1)
    #参与者分配到的元素
    pAssignedElements = [[] for i in range(n)]
    #ASC方法
    list1 = list(range(0,n))
    list3 = []
    for list2 in itertools.combinations(list1, t - 1):
        print(list2)
        list3.append(list(list2))
    print(list3)
    for i in range(0,N):
        for j in list3[i]:
            CombiTypes[i,j] = 1
    #ASC-2方法
    for i2 in range(1,d):
        for i3 in range(0,N):
            CombiTypes[i2 * N + i3] = CombiTypes[i3]
    #reverse
    CombiTypes = 1 - CombiTypes

    i5 = 0
    for list4 in CombiTypes:
        print(i5)
        print(list4)
        i5 += 1
    print(time.time())
    #分配元素
    for i in range(0,n,1): #n个参与者
        for j in range(0,d * N,1):#总元素个数
            if CombiTypes[j,i] == 1:  #CombiTypes = np.zeros([d * N ,n])
                pAssignedElements[i].append(PrimeNumbers[j])
    print(pAssignedElements)
    print(time.time())
    #密钥
    Pkey = 1
    for i in range(0, len(PrimeNumbers) ,1):
        Pkey *=PrimeNumbers[i]
    Pkey = hashlib.sha256(str(Pkey).encode('utf8')).hexdigest()  


    def RecoverSI(listParticipants):
        #计算第一个参与者的生成信息
        I = 1
        for i in range(0, len(pAssignedElements[0]) ,1):
            I *=pAssignedElements[listParticipants[0]][i]
        print(I)
        print(time.time())
        #剩余参与者的处理
        for j in range(1, len(listParticipants) ,1): #参与者
            for i in range(0, len(pAssignedElements[0]) ,1): #参与者原始集合
                tmp = pAssignedElements[listParticipants[j]][i]
                if  I % tmp != 0:
                    I *=tmp
        I = hashlib.sha256(str(I).encode('utf8')).hexdigest()         
        print(Pkey)
        print(I)
        return (I == Pkey)

    #t个参与者一起计算密钥
    #随机选择t个参与者
    listP = [x for x in range(0,n,1)]  #list for all participants
    listParticipants = random.sample(listP, t)  #从list中随机获取t个元素，作为一个片断返回
    print(listParticipants)
    print(time.time())
    print("Recover status：%d" % (RecoverSI(listParticipants)))

    listPall = list(range(0,n))
    #选出所有不少于t个参与者的组合
    listPnotLessThanT = []
    for j in range(0,n - t + 1,1):
        for listTmp in itertools.combinations(list1, t + j):
            listPnotLessThanT.append(list(listTmp))

    for listP in listPnotLessThanT:
        rst = RecoverSI(listP)
        assert(rst)
    #选出所有少于t个参与者的组合
    listPLessThanT = []
    for j in range(1,t,1):
        for listTmp in itertools.combinations(list1, t - j):
            listPLessThanT.append(list(listTmp))

    for listP in listPLessThanT:
        rst = RecoverSI(listP)
        assert(not rst)

    #set1 = set(PrimeNumbers)
    #set1 = sorted(set1)
    #print(set1)
    #set2 = set()
    #for j in range(0, len(sliceP) ,1): #参与者
    #    set2 = set2 |set(pAssignedElements[sliceP[j]])
    #set2 = sorted(set2)
    #print(set2)

    final = time.time()
    #print('运行时间'+str(round(final-frist,4))+'s')
    timeConsumed = final - frist
    rstStr = "t=%d, n=%d, d=%d ,int1=%e,int2=%e time=%.4f\n" % (t,n,d,int1,int2,timeConsumed)
    print(rstStr)
    with open('result.txt','a+')as g: #追加内容
        g.write(rstStr)
        g.close()
print("all finished")